home *** CD-ROM | disk | FTP | other *** search
/ The Utilities Experience / The Utilities Experience - Volume 1.iso / software / emulation / frodo / src / sam.c < prev    next >
C/C++ Source or Header  |  1996-02-10  |  46KB  |  1,978 lines

  1. /*
  2.  *  SAM.c - Simple Assembler and Monitor With Integrated System Explorer
  3.  *
  4.  *  Copyright (C) 1994-1996 by Christian Bauer
  5.  */
  6.  
  7. #include <exec/types.h>
  8. #include <clib/dos_protos.h>
  9. #include <clib/utility_protos.h>
  10.  
  11. #include "SAM.h"
  12. #include "6526.h"
  13. #include "6581.h"
  14. #include "6569.h"
  15.  
  16.  
  17. // Aus 6510.asm
  18. extern UBYTE RA, RX, RY, RP, RPR, RDDR;
  19. extern UWORD RPC, RS;
  20. extern UBYTE SAMReadByte(UWORD address);
  21. extern void SAMWriteByte(UWORD address, UBYTE byte);
  22. extern UBYTE SAMMemConfig;
  23.  
  24.  
  25. // Prototypes
  26. void error(char *s);            // Scanner
  27. BOOL aborted(void);
  28. void read_line(void);
  29. char get_char(void);
  30. void put_back(char c);
  31. enum Token get_token(void);
  32. enum RegToken get_reg_token(void);
  33. UWORD get_number(void);
  34. enum Token get_string(char *str);
  35.  
  36. BOOL expression(UWORD *number);    // Parser
  37. BOOL term(UWORD *number);
  38. BOOL factor(UWORD *number);
  39. BOOL address_args(void);
  40. BOOL range_args(int def_range);
  41. BOOL instr_args(UWORD *number, char *mode);
  42.  
  43. void help(void);                // Routinen für die Befehle
  44. void registers(void);
  45. void display_registers(void);
  46. void memory_dump(void);
  47. void ascii_dump(void);
  48. char conv_from_64(char c);
  49. void screen_dump(void);
  50. char conv_from_scode(char c);
  51. void binary_dump(void);
  52. void sprite_dump(void);
  53. void byte_to_bin(UBYTE byte, char *str);
  54. void disassemble(void);
  55. int disass_line(UWORD adr, UBYTE op, UBYTE lo, UBYTE hi);
  56. void assemble(void);
  57. char find_mnemonic(char op1, char op2, char op3);
  58. BOOL find_opcode(char mnem, char mode, UBYTE *opcode);
  59. void mem_config(void);
  60. void fill(void);
  61. void compare(void);
  62. void transfer(void);
  63. void modify(void);
  64. void print_expr(void);
  65. void redir_output(void);
  66. void int_vectors(void);
  67. void view_state(void);
  68. void view_cia_state(void);
  69. void dump_cia_ints(UBYTE int);
  70. void view_sid_state(void);
  71. void dump_sid_waveform(UBYTE wave);
  72. void view_vic_state(void);
  73. void dump_spr_flags(UBYTE f);
  74. void dump_vic_ints(UBYTE int);
  75. void load_data(void);
  76. void save_data(void);
  77.  
  78.  
  79. // FileHandles für Eingabe, Ausgabe und Fehler
  80. BPTR fin, fout, ferr;
  81.  
  82. // Eingabezeile
  83. #define INPUT_LENGTH 80
  84. char input[INPUT_LENGTH];
  85. char *in_ptr;
  86.  
  87. UWORD address, end_address;
  88.  
  89. // Eingabetoken
  90. enum Token {
  91.   T_NULL,        // Ungültiges Token
  92.   T_END,        // Ende der Zeile
  93.   T_NUMBER,        // Hexadezimalzahl
  94.   T_STRING,     // In "" eingeschlossener String
  95.   T_LPAREN,        // '('
  96.   T_RPAREN,        // ')'
  97.   T_ADD,        // '+'
  98.   T_SUB,        // '-'
  99.   T_MUL,        // '*'
  100.   T_DIV,        // '/'
  101.   T_COMMA,        // ','
  102.   T_IMMED,        // '#'
  103.   T_X,            // 'x'
  104.   T_Y,            // 'y'
  105.   T_PC,            // 'pc'
  106.   T_SP            // 'sp'
  107. };
  108.  
  109. // Registernamen
  110. enum RegToken {
  111.   RT_NULL,        // Ungültiges Token
  112.   RT_END,        // Ende der Zeile
  113.   RT_A,            // 'a'
  114.   RT_X,            // 'x'
  115.   RT_Y,            // 'y'
  116.   RT_PC,        // 'pc'
  117.   RT_SP,        // 'sp'
  118.   RT_DR,        // 'dr'
  119.   RT_PR            // 'pr'
  120. };
  121.  
  122. enum Token the_token;            // Auch RegToken für get_reg_token
  123. UWORD the_number;                // Enthält die Zahl, wenn the_token==T_NUMBER
  124. char the_string[INPUT_LENGTH];    // Enthält den String, wenn the_token==T_STRING
  125.  
  126. // Adressierungsarten
  127. enum {
  128.   A_IMPL,
  129.   A_ACCU,    // A
  130.   A_IMM,    // #zz
  131.   A_REL,    // Branches
  132.   A_ZERO,    // zz
  133.   A_ZEROX,    // zz,x
  134.   A_ZEROY,    // zz,y
  135.   A_ABS,    // zzzz
  136.   A_ABSX,    // zzzz,x
  137.   A_ABSY,    // zzzz,y
  138.   A_IND,    // (zzzz)
  139.   A_INDX,    // (zz,x)
  140.   A_INDY    // (zz),y
  141. };
  142.  
  143. // Mnemonics
  144. enum {
  145.   M_ADC, M_AND, M_ASL, M_BCC, M_BCS, M_BEQ, M_BIT, M_BMI, M_BNE, M_BPL,
  146.   M_BRK, M_BVC, M_BVS, M_CLC, M_CLD, M_CLI, M_CLV, M_CMP, M_CPX, M_CPY,
  147.   M_DEC, M_DEX, M_DEY, M_EOR, M_INC, M_INX, M_INY, M_JMP, M_JSR, M_LDA,
  148.   M_LDX, M_LDY, M_LSR, M_NOP, M_ORA, M_PHA, M_PHP, M_PLA, M_PLP, M_ROL,
  149.   M_ROR, M_RTI, M_RTS, M_SBC, M_SEC, M_SED, M_SEI, M_STA, M_STX, M_STY,
  150.   M_TAX, M_TAY, M_TSX, M_TXA, M_TXS, M_TYA,
  151.  
  152.   M_ILLEGAL,  // Ab hier kommen die undokumentierten Opcodes
  153.  
  154.   M_IANC, M_IANE, M_IARR, M_IASR, M_IDCP, M_IISB, M_IJAM, M_INOP, M_ILAS,
  155.   M_ILAX, M_ILXA, M_IRLA, M_IRRA, M_ISAX, M_ISBC, M_ISBX, M_ISHA, M_ISHS,
  156.   M_ISHX, M_ISHY, M_ISLO, M_ISRE,
  157.  
  158.   M_MAXIMUM  // Höchstes Element
  159. };
  160.  
  161. // Zu jedem Opcode das Mnemonic
  162. const char mnemonic[256] = {
  163.   M_BRK , M_ORA , M_IJAM, M_ISLO, M_INOP, M_ORA, M_ASL , M_ISLO,    // 00
  164.   M_PHP , M_ORA , M_ASL , M_IANC, M_INOP, M_ORA, M_ASL , M_ISLO,
  165.   M_BPL , M_ORA , M_IJAM, M_ISLO, M_INOP, M_ORA, M_ASL , M_ISLO,    // 10
  166.   M_CLC , M_ORA , M_INOP, M_ISLO, M_INOP, M_ORA, M_ASL , M_ISLO,
  167.   M_JSR , M_AND , M_IJAM, M_IRLA, M_BIT , M_AND, M_ROL , M_IRLA,    // 20
  168.   M_PLP , M_AND , M_ROL , M_IANC, M_BIT , M_AND, M_ROL , M_IRLA,
  169.   M_BMI , M_AND , M_IJAM, M_IRLA, M_INOP, M_AND, M_ROL , M_IRLA,    // 30
  170.   M_SEC , M_AND , M_INOP, M_IRLA, M_INOP, M_AND, M_ROL , M_IRLA,
  171.   M_RTI , M_EOR , M_IJAM, M_ISRE, M_INOP, M_EOR, M_LSR , M_ISRE,    // 40
  172.   M_PHA , M_EOR , M_LSR , M_IASR, M_JMP , M_EOR, M_LSR , M_ISRE,
  173.   M_BVC , M_EOR , M_IJAM, M_ISRE, M_INOP, M_EOR, M_LSR , M_ISRE,    // 50
  174.   M_CLI , M_EOR , M_INOP, M_ISRE, M_INOP, M_EOR, M_LSR , M_ISRE,
  175.   M_RTS , M_ADC , M_IJAM, M_IRRA, M_INOP, M_ADC, M_ROR , M_IRRA,    // 60
  176.   M_PLA , M_ADC , M_ROR , M_IARR, M_JMP , M_ADC, M_ROR , M_IRRA,
  177.   M_BVS , M_ADC , M_IJAM, M_IRRA, M_INOP, M_ADC, M_ROR , M_IRRA,    // 70
  178.   M_SEI , M_ADC , M_INOP, M_IRRA, M_INOP, M_ADC, M_ROR , M_IRRA,
  179.   M_INOP, M_STA , M_INOP, M_ISAX, M_STY , M_STA, M_STX , M_ISAX,    // 80
  180.   M_DEY , M_INOP, M_TXA , M_IANE, M_STY , M_STA, M_STX , M_ISAX,
  181.   M_BCC , M_STA , M_IJAM, M_ISHA, M_STY , M_STA, M_STX , M_ISAX,    // 90
  182.   M_TYA , M_STA , M_TXS , M_ISHS, M_ISHY, M_STA, M_ISHX, M_ISHA,
  183.   M_LDY , M_LDA , M_LDX , M_ILAX, M_LDY , M_LDA, M_LDX , M_ILAX,    // a0
  184.   M_TAY , M_LDA , M_TAX , M_ILXA, M_LDY , M_LDA, M_LDX , M_ILAX,
  185.   M_BCS , M_LDA , M_IJAM, M_ILAX, M_LDY , M_LDA, M_LDX , M_ILAX,    // b0
  186.   M_CLV , M_LDA , M_TSX , M_ILAS, M_LDY , M_LDA, M_LDX , M_ILAX,
  187.   M_CPY , M_CMP , M_INOP, M_IDCP, M_CPY , M_CMP, M_DEC , M_IDCP,    // c0
  188.   M_INY , M_CMP , M_DEX , M_ISBX, M_CPY , M_CMP, M_DEC , M_IDCP,
  189.   M_BNE , M_CMP , M_IJAM, M_IDCP, M_INOP, M_CMP, M_DEC , M_IDCP,    // d0
  190.   M_CLD , M_CMP , M_INOP, M_IDCP, M_INOP, M_CMP, M_DEC , M_IDCP,
  191.   M_CPX , M_SBC , M_INOP, M_IISB, M_CPX , M_SBC, M_INC , M_IISB,    // e0
  192.   M_INX , M_SBC , M_NOP , M_ISBC, M_CPX , M_SBC, M_INC , M_IISB,
  193.   M_BEQ , M_SBC , M_IJAM, M_IISB, M_INOP, M_SBC, M_INC , M_IISB,    // f0
  194.   M_SED , M_SBC , M_INOP, M_IISB, M_INOP, M_SBC, M_INC , M_IISB
  195. };
  196.  
  197. // Zu jedem Opcode die Adressierungsart
  198. const char adr_mode[256] = {
  199.   A_IMPL, A_INDX, A_IMPL, A_INDX, A_ZERO , A_ZERO , A_ZERO , A_ZERO,    // 00
  200.   A_IMPL, A_IMM , A_ACCU, A_IMM , A_ABS  , A_ABS  , A_ABS  , A_ABS,
  201.   A_REL , A_INDY, A_IMPL, A_INDY, A_ZEROX, A_ZEROX, A_ZEROX, A_ZEROX,    // 10
  202.   A_IMPL, A_ABSY, A_IMPL, A_ABSY, A_ABSX , A_ABSX , A_ABSX , A_ABSX,
  203.   A_ABS , A_INDX, A_IMPL, A_INDX, A_ZERO , A_ZERO , A_ZERO , A_ZERO,    // 20
  204.   A_IMPL, A_IMM , A_ACCU, A_IMM , A_ABS  , A_ABS  , A_ABS  , A_ABS,
  205.   A_REL , A_INDY, A_IMPL, A_INDY, A_ZEROX, A_ZEROX, A_ZEROX, A_ZEROX,    // 30
  206.   A_IMPL, A_ABSY, A_IMPL, A_ABSY, A_ABSX , A_ABSX , A_ABSX , A_ABSX,
  207.   A_IMPL, A_INDX, A_IMPL, A_INDX, A_ZERO , A_ZERO , A_ZERO , A_ZERO,    // 40
  208.   A_IMPL, A_IMM , A_ACCU, A_IMM , A_ABS  , A_ABS  , A_ABS  , A_ABS,
  209.   A_REL , A_INDY, A_IMPL, A_INDY, A_ZEROX, A_ZEROX, A_ZEROX, A_ZEROX,    // 50
  210.   A_IMPL, A_ABSY, A_IMPL, A_ABSY, A_ABSX , A_ABSX , A_ABSX , A_ABSX,
  211.   A_IMPL, A_INDX, A_IMPL, A_INDX, A_ZERO , A_ZERO , A_ZERO , A_ZERO,    // 60
  212.   A_IMPL, A_IMM , A_ACCU, A_IMM , A_IND  , A_ABS  , A_ABS  , A_ABS,
  213.   A_REL , A_INDY, A_IMPL, A_INDY, A_ZEROX, A_ZEROX, A_ZEROX, A_ZEROX,    // 70
  214.   A_IMPL, A_ABSY, A_IMPL, A_ABSY, A_ABSX , A_ABSX , A_ABSX , A_ABSX,
  215.   A_IMM , A_INDX, A_IMM , A_INDX, A_ZERO , A_ZERO , A_ZERO , A_ZERO,    // 80
  216.   A_IMPL, A_IMM , A_IMPL, A_IMM , A_ABS  , A_ABS  , A_ABS  , A_ABS,
  217.   A_REL , A_INDY, A_IMPL, A_INDY, A_ZEROX, A_ZEROX, A_ZEROY, A_ZEROY,    // 90
  218.   A_IMPL, A_ABSY, A_IMPL, A_ABSY, A_ABSX , A_ABSX , A_ABSY , A_ABSY,
  219.   A_IMM , A_INDX, A_IMM , A_INDX, A_ZERO , A_ZERO , A_ZERO , A_ZERO,    // a0
  220.   A_IMPL, A_IMM , A_IMPL, A_IMM , A_ABS  , A_ABS  , A_ABS  , A_ABS,
  221.   A_REL , A_INDY, A_IMPL, A_INDY, A_ZEROX, A_ZEROX, A_ZEROY, A_ZEROY,    // b0
  222.   A_IMPL, A_ABSY, A_IMPL, A_ABSY, A_ABSX , A_ABSX , A_ABSY , A_ABSY,
  223.   A_IMM , A_INDX, A_IMM , A_INDX, A_ZERO , A_ZERO , A_ZERO , A_ZERO,    // c0
  224.   A_IMPL, A_IMM , A_IMPL, A_IMM , A_ABS  , A_ABS  , A_ABS  , A_ABS,
  225.   A_REL , A_INDY, A_IMPL, A_INDY, A_ZEROX, A_ZEROX, A_ZEROX, A_ZEROX,    // d0
  226.   A_IMPL, A_ABSY, A_IMPL, A_ABSY, A_ABSX , A_ABSX , A_ABSX , A_ABSX,
  227.   A_IMM , A_INDX, A_IMM , A_INDX, A_ZERO , A_ZERO , A_ZERO , A_ZERO,    // e0
  228.   A_IMPL, A_IMM , A_IMPL, A_IMM , A_ABS  , A_ABS  , A_ABS  , A_ABS,
  229.   A_REL , A_INDY, A_IMPL, A_INDY, A_ZEROX, A_ZEROX, A_ZEROX, A_ZEROX,    // f0
  230.   A_IMPL, A_ABSY, A_IMPL, A_ABSY, A_ABSX , A_ABSX , A_ABSX , A_ABSX
  231. };
  232.  
  233. // Zu jedem Mnemonic die Zeichen
  234. const char mnem_1[] = "aaabbbbbbbbbbcccccccdddeiiijjllllnopppprrrrssssssstttttt?aaaadijnlllrrsssssssss";
  235. const char mnem_2[] = "dnscceimnprvvllllmppeeeonnnmsdddsorhhlloottbeeetttaasxxy?nnrscsaoaaxlrabbhhhhlr";
  236. const char mnem_3[] = "cdlcsqtielkcscdivpxycxyrcxypraxyrpaapaplrisccdiaxyxyxasa?cerrpbmpsxaaaxcxasxyoe";
  237.  
  238. // Zu jeder Adressierungsart die Befehlslänge
  239. const char adr_length[] = {1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 2, 2};
  240.  
  241.  
  242. /*
  243.  *  SAM öffnen und handhaben
  244.  */
  245.  
  246. void SAM(void)
  247. {
  248.   BOOL done = FALSE;
  249.   char c;
  250.  
  251.   if (fin = fout = ferr = Open("CON:0/0/640/480/SAM", MODE_NEWFILE)) {
  252.     FPuts(ferr, "\n *** SAM - Simple Assembler and Monitor ***\n ***         Press 'h' for help         ***\n\n");
  253.     display_registers();
  254.  
  255.     address = RPC;
  256.  
  257.     while (!done) {
  258.       Write(ferr, "> ", 2);
  259.       read_line();
  260.       while ((c = get_char()) == ' ') ;
  261.  
  262.       switch (c) {
  263.         case 'a':        // Assemblieren
  264.           get_token();
  265.           assemble();
  266.           break;
  267.  
  268.         case 'b':        // Binär-Dump
  269.           get_token();
  270.           binary_dump();
  271.           break;
  272.  
  273.         case 'c':        // Vergleichen
  274.           get_token();
  275.           compare();
  276.           break;
  277.  
  278.         case 'd':        // Disassemblieren
  279.           get_token();
  280.           disassemble();
  281.           break;
  282.  
  283.         case 'e':       // Interrupt-Vektoren
  284.           int_vectors();
  285.           break;
  286.  
  287.         case 'f':        // Füllen
  288.           get_token();
  289.           fill();
  290.           break;
  291.  
  292.         case 'h':        // Help
  293.           help();
  294.           break;
  295.  
  296.         case 'i':        // ASCII-Dump
  297.           get_token();
  298.           ascii_dump();
  299.           break;
  300.  
  301.         case 'k':        // Speicherkonfiguration
  302.           get_token();
  303.           mem_config();
  304.           break;
  305.  
  306.         case 'l':        // Daten laden
  307.           get_token();
  308.           load_data();
  309.           break;
  310.  
  311.         case 'm':        // Memory-Dump
  312.           get_token();
  313.           memory_dump();
  314.           break;
  315.  
  316.         case 'n':        // Screen-Code-Dump
  317.           get_token();
  318.           screen_dump();
  319.           break;
  320.  
  321.         case 'o':        // Ausgabe umleiten
  322.           get_token();
  323.           redir_output();
  324.           break;
  325.  
  326.         case 'p':        // Sprite-Dump
  327.           get_token();
  328.           sprite_dump();
  329.           break;
  330.  
  331.         case 'r':        // Register
  332.           get_reg_token();
  333.           registers();
  334.           break;
  335.  
  336.         case 's':        // Daten speichern
  337.           get_token();
  338.           save_data();
  339.           break;
  340.  
  341.         case 't':        // Transfer
  342.           get_token();
  343.           transfer();
  344.           break;
  345.  
  346.         case 'v':        // View machine state
  347.           view_state();
  348.           break;
  349.  
  350.         case 'x':        // Exit
  351.           done = TRUE;
  352.           break;
  353.  
  354.         case ':':        // Ändern
  355.           get_token();
  356.           modify();
  357.           break;
  358.  
  359.         case '?':        // Ausdruck berechnen
  360.           get_token();
  361.           print_expr();
  362.           break;
  363.  
  364.         case '\n':        // Leerzeile
  365.           break;
  366.  
  367.         default:        // Unbekannter Befehl
  368.           error("Unknown command");
  369.           break;
  370.       }
  371.     }
  372.  
  373.     Close(fin);
  374.     if (fout != ferr)
  375.       Close(fout);
  376.   }
  377. }
  378.  
  379.  
  380. /*
  381.  *  Fehlermeldung ausgeben
  382.  */
  383.  
  384. void error(char *s)
  385. {
  386.   FPrintf(ferr, "*** %s\n", s);
  387. }
  388.  
  389.  
  390. /*
  391.  *  CTRL-C gedrückt?
  392.  */
  393.  
  394. #include <dos/dos.h>
  395. #include <clib/exec_protos.h>
  396. BOOL aborted(void)
  397. {
  398.   return SetSignal(0, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C;
  399. }
  400.  
  401.  
  402. /*
  403.  *  Eine Zeile von der Tastatur lesen
  404.  */
  405.  
  406. void read_line(void)
  407. {
  408.   FGets(fin, in_ptr = input, INPUT_LENGTH);
  409. }
  410.  
  411.  
  412. /*
  413.  *  Ein Zeichen aus der Eingabezeile lesen
  414.  */
  415.  
  416. char get_char(void)
  417. {
  418.   return *in_ptr++;
  419. }
  420.  
  421.  
  422. /*
  423.  *  Zeichen in die Eingabezeile zurückpacken
  424.  */
  425.  
  426. void put_back(char c)
  427. {
  428.   *(--in_ptr) = c;
  429. }
  430.  
  431.  
  432. /*
  433.  *  Scanner: Ein Token aus der Eingabezeile lesen
  434.  */
  435.  
  436. enum Token get_token(void)
  437. {
  438.   char c;
  439.  
  440.   // Leerzeichen überspringen
  441.   while ((c = get_char()) == ' ') ;
  442.  
  443.   switch (ToLower(c)) {
  444.     case '\n':
  445.       return the_token = T_END;
  446.     case '(':
  447.       return the_token = T_LPAREN;
  448.     case ')':
  449.       return the_token = T_RPAREN;
  450.     case '+':
  451.       return the_token = T_ADD;
  452.     case '-':
  453.       return the_token = T_SUB;
  454.     case '*':
  455.       return the_token = T_MUL;
  456.     case '/':
  457.       return the_token = T_DIV;
  458.     case ',':
  459.       return the_token = T_COMMA;
  460.     case '#':
  461.       return the_token = T_IMMED;
  462.     case 'x':
  463.       return the_token = T_X;
  464.     case 'y':
  465.       return the_token = T_Y;
  466.     case 'p':
  467.       if (ToLower(get_char()) == 'c')
  468.         return the_token = T_PC;
  469.       else {
  470.         error("Unrecognized token");
  471.         return the_token = T_NULL;
  472.       }
  473.     case 's':
  474.       if (ToLower(get_char()) == 'p')
  475.         return the_token = T_SP;
  476.       else {
  477.         error("Unrecognized token");
  478.         return the_token = T_NULL;
  479.       }
  480.     case '0': case '1': case '2': case '3': case '4':
  481.     case '5': case '6': case '7': case '8': case '9':
  482.     case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
  483.       put_back(c);
  484.       the_number = get_number();
  485.       return the_token = T_NUMBER;
  486.     case '"':
  487.       return the_token = get_string(the_string);
  488.     default:
  489.       error("Unrecognized token");
  490.       return the_token = T_NULL;
  491.   }
  492. }
  493.  
  494. enum RegToken get_reg_token(void)
  495. {
  496.   char c;
  497.  
  498.   // Leerzeichen überspringen
  499.   while ((c = get_char()) == ' ') ;
  500.  
  501.   switch (ToLower(c)) {
  502.     case '\n':
  503.       return the_token = RT_END;
  504.     case 'a':
  505.       return the_token = RT_A;
  506.     case 'd':
  507.       if (ToLower(get_char()) == 'r')
  508.         return the_token = RT_DR;
  509.       else {
  510.         error("Unrecognized token");
  511.         return the_token = RT_NULL;
  512.       }
  513.     case 'p':
  514.       if ((c = ToLower(get_char())) == 'c')
  515.         return the_token = RT_PC;
  516.       else if (c == 'r')
  517.         return the_token = RT_PR;
  518.       else {
  519.         error("Unrecognized token");
  520.         return the_token = RT_NULL;
  521.       }
  522.     case 's':
  523.       if (ToLower(get_char()) == 'p')
  524.         return the_token = RT_SP;
  525.       else {
  526.         error("Unrecognized token");
  527.         return the_token = RT_NULL;
  528.       }
  529.     case 'x':
  530.       return the_token = RT_X;
  531.     case 'y':
  532.       return the_token = RT_Y;
  533.     default:
  534.       error("Unrecognized token");
  535.       return the_token = RT_NULL;
  536.   }
  537. }
  538.  
  539. UWORD get_number(void)
  540. {
  541.   char c;
  542.   UWORD i = 0;
  543.  
  544.   while (((c = ToLower(get_char())) >= '0') && (c <= '9') || (c >= 'a') && (c <= 'f'))
  545.     if (c < 'a')
  546.       i = (i << 4) + (c - '0');
  547.     else
  548.       i = (i << 4) + (c - 'a' + 10);
  549.  
  550.   put_back(c);
  551.   return i;
  552. }
  553.  
  554. enum Token get_string(char *str)
  555. {
  556.   char c;
  557.  
  558.   while ((c = get_char()) != '\n') {
  559.     if (c == '"') {
  560.       *str = 0;
  561.       return T_STRING;
  562.     }
  563.     *str++ = c;
  564.   }
  565.  
  566.   error("Unterminated string");
  567.   return T_NULL;
  568. }
  569.  
  570.  
  571. /*
  572.  *  expression = term {(ADD | SUB) term}
  573.  *  TRUE: OK, FALSE: Fehler
  574.  */
  575.  
  576. BOOL expression(UWORD *number)
  577. {
  578.   UWORD accu, trm;
  579.  
  580.   if (!term(&accu))
  581.     return FALSE;
  582.  
  583.   for (;;)
  584.     switch (the_token) {
  585.       case T_ADD:
  586.         get_token();
  587.         if (!term(&trm))
  588.           return FALSE;
  589.         accu += trm;
  590.         break;
  591.  
  592.       case T_SUB:
  593.         get_token();
  594.         if (!term(&trm))
  595.           return FALSE;
  596.         accu -= trm;
  597.         break;
  598.  
  599.       default:
  600.         *number = accu;
  601.         return TRUE;
  602.     }
  603. }
  604.  
  605.  
  606. /*
  607.  *  term = factor {(MUL | DIV) factor}
  608.  *  TRUE: OK, FALSE: Fehler
  609.  */
  610.  
  611. BOOL term(UWORD *number)
  612. {
  613.   UWORD accu, fact;
  614.  
  615.   if (!factor(&accu))
  616.     return FALSE;
  617.  
  618.   for (;;)
  619.     switch (the_token) {
  620.       case T_MUL:
  621.         get_token();
  622.         if (!factor(&fact))
  623.           return FALSE;
  624.         accu *= fact;
  625.         break;
  626.  
  627.       case T_DIV:
  628.         get_token();
  629.         if (!factor(&fact))
  630.           return FALSE;
  631.         if (fact == 0) {
  632.           error("Division by 0");
  633.           return FALSE;
  634.         }
  635.         accu /= fact;
  636.         break;
  637.  
  638.       default:
  639.         *number = accu;
  640.         return TRUE;
  641.     }
  642. }
  643.  
  644.  
  645. /*
  646.  *  factor = NUMBER | PC | SP | LPAREN expression RPAREN
  647.  *  TRUE: OK, FALSE: Fehler
  648.  */
  649.  
  650. BOOL factor(UWORD *number)
  651. {
  652.   switch (the_token) {
  653.     case T_NUMBER:
  654.       *number = the_number;
  655.       get_token();
  656.       return TRUE;
  657.  
  658.     case T_PC:
  659.       get_token();
  660.       *number = RPC;
  661.       return TRUE;
  662.  
  663.     case T_SP:
  664.       get_token();
  665.       *number = RS;
  666.       return TRUE;
  667.  
  668.     case T_LPAREN:
  669.       get_token();
  670.       if (expression(number))
  671.         if (the_token == T_RPAREN) {
  672.           get_token();
  673.           return TRUE;
  674.         } else {
  675.           error("Missing ')'");
  676.           return FALSE;
  677.         }
  678.       else {
  679.         error("Error in expression");
  680.         return FALSE;
  681.       }
  682.  
  683.     case T_END:
  684.       error("Required argument missing");
  685.       return FALSE;
  686.  
  687.     default:
  688.       error("'pc', 'sp', '(' or number expected");
  689.       return FALSE;
  690.   }
  691. }
  692.  
  693.  
  694. /*
  695.  *  address_args = [expression] END
  696.  *
  697.  *  Startadresse nach address lesen
  698.  *
  699.  *  TRUE: OK, FALSE: Fehler
  700.  */
  701.  
  702. BOOL address_args(void)
  703. {
  704.   if (the_token == T_END)
  705.     return TRUE;
  706.   else {
  707.     if (!expression(&address))
  708.       return FALSE;
  709.     return the_token == T_END;
  710.   }
  711. }
  712.  
  713.  
  714. /*
  715.  *  range_args = [expression] [[COMMA] expression] END
  716.  *
  717.  *  Startadresse nach address, Endadresse nach end_address lesen
  718.  *
  719.  *  TRUE: OK, FALSE: Fehler
  720.  */
  721.  
  722. BOOL range_args(int def_range)
  723. {
  724.   end_address = address + def_range;
  725.  
  726.   if (the_token == T_END)
  727.     return TRUE;
  728.   else {
  729.     if (!expression(&address))
  730.       return FALSE;
  731.     end_address = address + def_range;
  732.     if (the_token == T_END)
  733.       return TRUE;
  734.     else {
  735.       if (the_token == T_COMMA) get_token();
  736.       if (!expression(&end_address))
  737.         return FALSE;
  738.       return the_token == T_END;
  739.     }
  740.   }
  741. }
  742.  
  743.  
  744. /*
  745.  *  instr_args = END
  746.  *             | IMMED NUMBER END
  747.  *             | NUMBER [COMMA (X | Y)] END
  748.  *             | LPAREN NUMBER (RPAREN [COMMA Y] | COMMA X RPAREN) END
  749.  *
  750.  *  Argumente eines 6510-Befehls lesen, Adresse und Adressierungsart ermitteln
  751.  *
  752.  *  TRUE: OK, FALSE: Fehler
  753.  */
  754.  
  755. BOOL instr_args(UWORD *number, char *mode)
  756. {
  757.   switch (the_token) {
  758.  
  759.     case T_END:
  760.       *mode = A_IMPL;
  761.       return TRUE;
  762.  
  763.     case T_IMMED:
  764.       get_token();
  765.       if (the_token == T_NUMBER) {
  766.         *number = the_number;
  767.         *mode = A_IMM;
  768.         get_token();
  769.         return the_token == T_END;
  770.       } else {
  771.         error("Number expected");
  772.         return FALSE;
  773.       }
  774.  
  775.     case T_NUMBER:
  776.       *number = the_number;
  777.       get_token();
  778.       switch (the_token) {
  779.  
  780.         case T_END:
  781.           if (*number < 0x100)
  782.             *mode = A_ZERO;
  783.           else
  784.             *mode = A_ABS;
  785.           return TRUE;
  786.  
  787.         case T_COMMA:
  788.           get_token();
  789.           switch (the_token) {
  790.  
  791.             case T_X:
  792.               get_token();
  793.               if (*number < 0x100)
  794.                 *mode = A_ZEROX;
  795.               else
  796.                 *mode = A_ABSX;
  797.               return the_token == T_END;
  798.  
  799.             case T_Y:
  800.               get_token();
  801.               if (*number < 0x100)
  802.                 *mode = A_ZEROY;
  803.               else
  804.                 *mode = A_ABSY;
  805.               return the_token == T_END;
  806.  
  807.             default:
  808.               error("Illegal index register");
  809.               return FALSE;
  810.           }
  811.  
  812.         default:
  813.           return FALSE;
  814.       }
  815.  
  816.     case T_LPAREN:
  817.       get_token();
  818.       if (the_token == T_NUMBER) {
  819.         *number = the_number;
  820.         get_token();
  821.         switch (the_token) {
  822.           case T_RPAREN:
  823.             get_token();
  824.             switch (the_token) {
  825.  
  826.               case T_END:
  827.                 *mode = A_IND;
  828.                 return TRUE;
  829.  
  830.               case T_COMMA:
  831.                 get_token();
  832.                 if (the_token == T_Y) {
  833.                   *mode = A_INDY;
  834.                   get_token();
  835.                   return the_token == T_END;
  836.                 } else {
  837.                   error("Only 'y' index register allowed");
  838.                   return FALSE;
  839.                 }
  840.  
  841.               default:
  842.                 error("Illegal characters after ')'");
  843.                 return FALSE;
  844.             }
  845.  
  846.           case T_COMMA:
  847.             get_token();
  848.             if (the_token == T_X) {
  849.               get_token();
  850.               if (the_token == T_RPAREN) {
  851.                 *mode = A_INDX;
  852.                 get_token();
  853.                 return the_token == T_END;
  854.               } else {
  855.                 error("')' expected");
  856.                 return FALSE;
  857.               }
  858.             } else {
  859.               error("Only 'x' index register allowed");
  860.               return FALSE;
  861.             }
  862.  
  863.           default:
  864.             error("')' or ',' expected");
  865.             return FALSE;
  866.         }
  867.       } else {
  868.         error("Number expected");
  869.         return FALSE;
  870.       }
  871.  
  872.     default:
  873.       error("'(', '#' or number expected");
  874.       return FALSE;
  875.   }
  876. }
  877.  
  878.  
  879. /*
  880.  *  Hilfstext anzeigen
  881.  *  ?
  882.  */
  883.  
  884. void help(void)
  885. {
  886.   FPuts(fout, "a [start]           Assemble\n"
  887.               "b [start] [end]     Binary dump\n"
  888.               "c start end dest    Compare memory\n"
  889.               "d [start] [end]     Disassemble\n"
  890.               "e                   Show interrupt vectors\n"
  891.               "f start end byte    Fill memory\n"
  892.               "i [start] [end]     ASCII/PETSCII dump\n"
  893.               "k [config]          Show/set memory configuration\n"
  894.               "l start \"file\"      Load data\n"
  895.               "m [start] [end]     Memory dump\n"
  896.               "n [start] [end]     Screen code dump\n"
  897.               "o [\"file\"]          Redirect output\n"
  898.               "p [start] [end]     Sprite dump\n"
  899.               "r [reg value]       Show/set registers\n"
  900.               "s start end \"file\"  Save data\n"
  901.               "t start end dest    Transfer memory\n"
  902.               "vc1                 View CIA 1 state\n"
  903.               "vc2                 View CIA 2 state\n"
  904.               "vs                  View SID state\n"
  905.               "vv                  View VIC state\n"
  906.               "x                   Return to Frodo\n"
  907.               ": addr {byte}       Modify memory\n"
  908.               "? expression        Calculate expression\n");
  909. }
  910.  
  911.  
  912. /*
  913.  *  6510-Register anzeigen/ändern
  914.  *  r [reg value]
  915.  */
  916.  
  917. void registers(void)
  918. {
  919.   enum RegToken the_reg;
  920.   UWORD value;
  921.  
  922.   if (the_token != RT_END)
  923.     switch (the_reg = the_token) {
  924.       case RT_A:
  925.       case RT_X:
  926.       case RT_Y:
  927.       case RT_PC:
  928.       case RT_SP:
  929.       case RT_DR:
  930.       case RT_PR:
  931.         get_token();
  932.         if (!expression(&value))
  933.           return;
  934.  
  935.         switch (the_reg) {
  936.           case RT_A:
  937.             RA = value;
  938.             break;
  939.           case RT_X:
  940.             RX = value;
  941.             break;
  942.           case RT_Y:
  943.             RY = value;
  944.             break;
  945.           case RT_PC:
  946.             RPC = value;
  947.             break;
  948.           case RT_SP:
  949.             RS = (value & 0xff) | 0x0100;
  950.             break;
  951.           case RT_DR:
  952.             RDDR = value;
  953.             break;
  954.           case RT_PR:
  955.             RPR = value;
  956.             break;
  957.         }
  958.         break;
  959.  
  960.       default:
  961.         return;
  962.     }
  963.  
  964.   display_registers();
  965. }
  966.  
  967. void display_registers(void)
  968. {
  969.   FPuts(fout, " PC  A  X  Y   SP  DR PR NVDIZC  Instruction\n");
  970.   FPrintf(fout, "%04lx %02lx %02lx %02lx %04lx %02lx %02lx %lc%lc%lc%lc%lc%lc ",
  971.     RPC, RA, RX, RY, RS, RDDR, RPR,
  972.     RP & 0x80 ? '1' : '0', RP & 0x40 ? '1' : '0', RP & 0x08 ? '1' : '0',
  973.     RP & 0x04 ? '1' : '0', RP & 0x02 ? '1' : '0', RP & 0x01 ? '1' : '0');
  974.   disass_line(RPC, SAMReadByte(RPC), SAMReadByte(RPC+1), SAMReadByte(RPC+2));
  975. }
  976.  
  977.  
  978. /*
  979.  *  Memory-Dump
  980.  *  m [start] [end]
  981.  */
  982.  
  983. #define MEMDUMP_BPL 16  // Bytes pro Zeile
  984.  
  985. void memory_dump(void)
  986. {
  987.   BOOL done = FALSE;
  988.   short i;
  989.   UBYTE mem[MEMDUMP_BPL + 2];
  990.   UBYTE byte;
  991.  
  992.   mem[MEMDUMP_BPL] = 0;
  993.  
  994.   if (!range_args(16 * MEMDUMP_BPL - 1))  // 16 Zeilen, wenn keine Endadresse angegeben
  995.     return;
  996.  
  997.   do {
  998.     FPrintf(fout, "%04lx:", address);
  999.     for (i=0; i<MEMDUMP_BPL; i++, address++) {
  1000.       if (address == end_address) done = TRUE;
  1001.  
  1002.       FPrintf(fout, " %02lx", byte = SAMReadByte(address));
  1003.       if ((byte >= ' ') && (byte <= '~'))
  1004.         mem[i] = conv_from_64(byte);
  1005.       else
  1006.         mem[i] = '.';
  1007.     }
  1008.     FPrintf(fout, "  '%s'\n", mem);
  1009.   } while (!done && !aborted());
  1010. }
  1011.  
  1012.  
  1013. /*
  1014.  *  ASCII-Dump
  1015.  *  i [start] [end]
  1016.  */
  1017.  
  1018. #define ASCIIDUMP_BPL 64  // Bytes pro Zeile
  1019.  
  1020. void ascii_dump(void)
  1021. {
  1022.   BOOL done = FALSE;
  1023.   short i;
  1024.   UBYTE mem[ASCIIDUMP_BPL + 2];
  1025.   UBYTE byte;
  1026.  
  1027.   mem[ASCIIDUMP_BPL] = 0;
  1028.  
  1029.   if (!range_args(16 * ASCIIDUMP_BPL - 1))  // 16 Zeilen, wenn keine Endadresse angegeben
  1030.     return;
  1031.  
  1032.   do {
  1033.     FPrintf(fout, "%04lx:", address);
  1034.     for (i=0; i<ASCIIDUMP_BPL; i++, address++) {
  1035.       if (address == end_address) done = TRUE;
  1036.  
  1037.       byte = SAMReadByte(address);
  1038.       if ((byte >= ' ') && (byte <= '~'))
  1039.         mem[i] = conv_from_64(byte);
  1040.       else
  1041.         mem[i] = '.';
  1042.     }
  1043.     FPrintf(fout, " '%s'\n", mem);
  1044.   } while (!done && !aborted());
  1045. }
  1046.  
  1047.  
  1048. /*
  1049.  *  Umwandlung PETSCII->ASCII
  1050.  */
  1051.  
  1052. char conv_from_64(char c)
  1053. {
  1054.   if ((c >= 'A') && (c <= 'Z') || (c >= 'a') && (c <= 'z'))
  1055.     return c ^ 0x20;
  1056.   else
  1057.     return c;
  1058. }
  1059.  
  1060.  
  1061. /*
  1062.  *  Screen-Code-Dump
  1063.  *  n [start] [end]
  1064.  */
  1065.  
  1066. #define SCRDUMP_BPL 64  // Bytes pro Zeile
  1067.  
  1068. void screen_dump(void)
  1069. {
  1070.   BOOL done = FALSE;
  1071.   short i;
  1072.   UBYTE mem[SCRDUMP_BPL + 2];
  1073.   UBYTE byte;
  1074.  
  1075.   mem[SCRDUMP_BPL] = 0;
  1076.  
  1077.   if (!range_args(16 * SCRDUMP_BPL - 1))  // 16 Zeilen, wenn keine Endadresse angegeben
  1078.     return;
  1079.  
  1080.   do {
  1081.     FPrintf(fout, "%04lx:", address);
  1082.     for (i=0; i<SCRDUMP_BPL; i++, address++) {
  1083.       if (address == end_address) done = TRUE;
  1084.  
  1085.       byte = SAMReadByte(address);
  1086.       if (byte < 90)
  1087.         mem[i] = conv_from_scode(byte);
  1088.       else
  1089.         mem[i] = '.';
  1090.     }
  1091.     FPrintf(fout, " '%s'\n", mem);
  1092.   } while (!done && !aborted());
  1093. }
  1094.  
  1095.  
  1096. /*
  1097.  *  Umwandlung Bildschirmcode->ASCII
  1098.  */
  1099.  
  1100. char conv_from_scode(char c)
  1101. {
  1102.   c &= 0x7f;
  1103.  
  1104.   if (c <= 31)
  1105.     return c + 64;
  1106.   else
  1107.     if (c >= 64)
  1108.       return c + 32;
  1109.     else
  1110.       return c;
  1111. }
  1112.  
  1113.  
  1114. /*
  1115.  *  Binär-Dump
  1116.  *  b [start] [end]
  1117.  */
  1118.  
  1119. void binary_dump(void)
  1120. {
  1121.   BOOL done = FALSE;
  1122.   char bin[10];
  1123.  
  1124.   bin[8] = 0;
  1125.  
  1126.   if (!range_args(7))  // 8 Zeilen, wenn keine Endadresse angegeben
  1127.     return;
  1128.  
  1129.   do {
  1130.     if (address == end_address) done = TRUE;
  1131.  
  1132.     byte_to_bin(SAMReadByte(address), bin);
  1133.     FPrintf(fout, "%04lx: %s\n", address++, bin);
  1134.   } while (!done && !aborted());
  1135. }
  1136.  
  1137.  
  1138. /*
  1139.  *  Sprite-Daten-Dump
  1140.  *  p [start] [end]
  1141.  */
  1142.  
  1143. void sprite_dump(void)
  1144. {
  1145.   BOOL done = FALSE;
  1146.   short i;
  1147.   char bin[10];
  1148.  
  1149.   bin[8] = 0;
  1150.  
  1151.   if (!range_args(21 * 3 - 1))  // 21 Zeilen, wenn keine Endadresse angegeben
  1152.     return;
  1153.  
  1154.   do {
  1155.     FPrintf(fout, "%04lx: ", address);
  1156.     for (i=0; i<3; i++, address++) {
  1157.       if (address == end_address) done = TRUE;
  1158.  
  1159.       byte_to_bin(SAMReadByte(address), bin);
  1160.       FPrintf(fout, "%s", bin);
  1161.     }
  1162.     FPutC(fout, '\n');
  1163.   } while (!done && !aborted());
  1164. }
  1165.  
  1166.  
  1167. /*
  1168.  *  Ein Byte in Binärfolge umwandeln
  1169.  */
  1170.  
  1171. void byte_to_bin(UBYTE byte, char *str)
  1172. {
  1173.   short i;
  1174.  
  1175.   for (i=0; i<8; i++, byte<<=1)
  1176.     if (byte & 0x80)
  1177.       str[i] = '#';
  1178.     else
  1179.       str[i] = '.';
  1180. }
  1181.  
  1182.  
  1183. /*
  1184.  *  Disassemblieren
  1185.  *  d [start] [end]
  1186.  */
  1187.  
  1188. void disassemble(void)
  1189. {
  1190.   BOOL done = FALSE;
  1191.   short i;
  1192.   UBYTE op[3];
  1193.   UWORD adr;
  1194.  
  1195.   if (!range_args(31))  // 32 Bytes, wenn keine Endadresse angegeben
  1196.     return;
  1197.  
  1198.   do {
  1199.     FPrintf(fout, "%04lx:", adr = address);
  1200.     for (i=0; i<3; i++, adr++) {
  1201.       if (adr == end_address) done = TRUE;
  1202.       op[i] = SAMReadByte(adr);
  1203.     }
  1204.     address += disass_line(address, op[0], op[1], op[2]);
  1205.   } while (!done && !aborted());
  1206. }
  1207.  
  1208.  
  1209. /*
  1210.  *  Einen Befehl disassemblieren, Länge zurückgeben
  1211.  */
  1212.  
  1213. int disass_line(UWORD adr, UBYTE op, UBYTE lo, UBYTE hi)
  1214. {
  1215.   char mode = adr_mode[op], mnem = mnemonic[op];
  1216.  
  1217.   // Befehlsbytes hexadezimal ausgeben
  1218.   switch (adr_length[mode]) {
  1219.     case 1:
  1220.       FPrintf(fout, " %02lx       ", op);
  1221.       break;
  1222.  
  1223.     case 2:
  1224.       FPrintf(fout, " %02lx %02lx    ", op, lo);
  1225.       break;
  1226.  
  1227.     case 3:
  1228.       FPrintf(fout, " %02lx %02lx %02lx ", op, lo, hi);
  1229.       break;
  1230.   }
  1231.  
  1232.   // Undokumentierte Opcodes mit Stern markieren
  1233.   if (mnem > M_ILLEGAL)
  1234.     FPutC(fout, '*');
  1235.   else
  1236.     FPutC(fout, ' ');
  1237.  
  1238.   // Mnemonic ausgeben
  1239.   FPrintf(fout, "%lc%lc%lc ", mnem_1[mnem], mnem_2[mnem], mnem_3[mnem]);
  1240.  
  1241.   // Argument ausgeben
  1242.   switch (mode) {
  1243.     case A_IMPL:
  1244.       break;
  1245.  
  1246.     case A_ACCU:
  1247.       FPuts(fout, "a");
  1248.       break;
  1249.  
  1250.     case A_IMM:
  1251.       FPrintf(fout, "#%02lx", lo);
  1252.       break;
  1253.  
  1254.     case A_REL:
  1255.       FPrintf(fout, "%04lx", ((adr + 2) + (BYTE)lo) & 0xffff);
  1256.       break;
  1257.  
  1258.     case A_ZERO:
  1259.       FPrintf(fout, "%02lx", lo);
  1260.       break;
  1261.  
  1262.     case A_ZEROX:
  1263.       FPrintf(fout, "%02lx,x", lo);
  1264.       break;
  1265.  
  1266.     case A_ZEROY:
  1267.       FPrintf(fout, "%02lx,y", lo);
  1268.       break;
  1269.  
  1270.     case A_ABS:
  1271.       FPrintf(fout, "%04lx", (hi << 8) | lo);
  1272.       break;
  1273.  
  1274.     case A_ABSX:
  1275.       FPrintf(fout, "%04lx,x", (hi << 8) | lo);
  1276.       break;
  1277.  
  1278.     case A_ABSY:
  1279.       FPrintf(fout, "%04lx,y", (hi << 8) | lo);
  1280.       break;
  1281.  
  1282.     case A_IND:
  1283.       FPrintf(fout, "(%04lx)", (hi << 8) | lo);
  1284.       break;
  1285.  
  1286.     case A_INDX:
  1287.       FPrintf(fout, "(%02lx,x)", lo);
  1288.       break;
  1289.  
  1290.     case A_INDY:
  1291.       FPrintf(fout, "(%02lx),y", lo);
  1292.       break;
  1293.   }
  1294.  
  1295.   FPutC(fout, '\n');
  1296.   return adr_length[mode];
  1297. }
  1298.  
  1299.  
  1300. /*
  1301.  *  Assemblieren
  1302.  *  a [start]
  1303.  */
  1304.  
  1305. void assemble(void)
  1306. {
  1307.   BOOL done = FALSE;
  1308.   char c1, c2, c3;
  1309.   char mnem, mode;
  1310.   UBYTE opcode;
  1311.   UWORD arg;
  1312.   WORD rel;
  1313.  
  1314.   // Parameter lesen
  1315.   if (!address_args())
  1316.     return;
  1317.  
  1318.   do {
  1319.     FPrintf(fout, "%04lx> ", address);
  1320.     read_line();
  1321.  
  1322.     c1 = ToLower(get_char());
  1323.     c2 = ToLower(get_char());
  1324.     c3 = ToLower(get_char());
  1325.  
  1326.     if (c1 != '\n') {
  1327.  
  1328.       if ((mnem = find_mnemonic(c1, c2, c3)) != M_ILLEGAL) {
  1329.  
  1330.         get_token();
  1331.         if (instr_args(&arg, &mode)) {
  1332.  
  1333.           // Ggf. A_IMPL -> A_ACCU
  1334.           if ((mode == A_IMPL) && find_opcode(mnem, A_ACCU, &opcode))
  1335.             mode = A_ACCU;
  1336.  
  1337.           // Relative Adressierung getrennt behandeln
  1338.           if (((mode == A_ABS) || (mode == A_ZERO)) && find_opcode(mnem, A_REL, &opcode)) {
  1339.             mode = A_REL;
  1340.             rel = arg - (address + 2) & 0xffff;
  1341.             if ((rel < -128) || (rel > 127)) {
  1342.               error("Branch too long");
  1343.               continue;
  1344.             } else
  1345.               arg = rel & 0xff;
  1346.           }
  1347.  
  1348.           if (find_opcode(mnem, mode, &opcode)) {
  1349.  
  1350.             // Disassemblierte Zeile ausgeben
  1351.             FPrintf(fout, "\v%04lx:", address);
  1352.             disass_line(address, opcode, arg & 0xff, arg >> 8);
  1353.  
  1354.             switch (adr_length[mode]) {
  1355.               case 1:
  1356.                 SAMWriteByte(address++, opcode);
  1357.                 break;
  1358.  
  1359.               case 2:
  1360.                 SAMWriteByte(address++, opcode);
  1361.                 SAMWriteByte(address++, arg);
  1362.                 break;
  1363.  
  1364.               case 3:
  1365.                 SAMWriteByte(address++, opcode);
  1366.                 SAMWriteByte(address++, arg & 0xff);
  1367.                 SAMWriteByte(address++, arg >> 8);
  1368.                 break;
  1369.  
  1370.               default:
  1371.                 error("Internal error");
  1372.                 break;
  1373.             }
  1374.  
  1375.           } else    // Adressierungsart paßt nicht zum Befehl
  1376.             error("Addressing mode not supported by instruction");
  1377.  
  1378.         } else    // Nicht erkannte Adressierungsart
  1379.           error("Unrecognized addressing mode");
  1380.  
  1381.       } else        // Mnemonic nicht gefunden
  1382.         error("Unknown instruction");
  1383.  
  1384.     } else            // Leerzeile beendet die Eingabe
  1385.       done = TRUE;
  1386.   } while (!done);
  1387. }
  1388.  
  1389.  
  1390. /*
  1391.  *  Zu drei Buchstaben den passenden Mnemonic-Code finden
  1392.  *  M_ILLEGAL: Kein passendes Mnemonic gefunden
  1393.  */
  1394.  
  1395. char find_mnemonic(char op1, char op2, char op3)
  1396. {
  1397.   int i;
  1398.   char c1, c2, c3;
  1399.  
  1400.   for (i=0; i<M_MAXIMUM; i++)
  1401.     if ((mnem_1[i] == op1) && (mnem_2[i] == op2) && (mnem_3[i] == op3))
  1402.       return i;
  1403.  
  1404.   return M_ILLEGAL;
  1405. }
  1406.  
  1407.  
  1408. /*
  1409.  *  Opcode eines Befehls ermitteln, Mnemonic und Adressierungsart gegeben
  1410.  *  TRUE: OK, FALSE: Mnemonic kommt mit dieser Adressierungsart nicht vor
  1411.  */
  1412.  
  1413. BOOL find_opcode(char mnem, char mode, UBYTE *opcode)
  1414. {
  1415.   int i;
  1416.  
  1417.   for (i=0; i<256; i++)
  1418.     if ((mnemonic[i] == mnem) && (adr_mode[i] == mode)) {
  1419.       *opcode = i;
  1420.       return TRUE;
  1421.     }
  1422.  
  1423.   return FALSE;
  1424. }
  1425.  
  1426.  
  1427. /*
  1428.  *  Speicherkonfiguration anzeigen/setzen
  1429.  *  k [config]
  1430.  */
  1431.  
  1432. void mem_config(void)
  1433. {
  1434.   UWORD con;
  1435.  
  1436.   if (the_token != T_END)
  1437.     if (!expression(&con))
  1438.       return;
  1439.     else
  1440.       SAMMemConfig = con;
  1441.   else
  1442.     con = SAMMemConfig;
  1443.  
  1444.   FPrintf(fout, "Configuration: %ld\n", con & 7);
  1445.   FPrintf(fout, "A000-BFFF: %s\n", (con & 3) == 3 ? "Basic" : "RAM");
  1446.   FPrintf(fout, "D000-DFFF: %s\n", (con & 3) ? ((con & 4) ? "I/O" : "Char") : "RAM");
  1447.   FPrintf(fout, "E000-FFFF: %s\n", (con & 2) ? "Kernal" : "RAM");
  1448. }
  1449.  
  1450.  
  1451. /*
  1452.  *  Füllen
  1453.  *  k start end byte
  1454.  */
  1455.  
  1456. void fill(void)
  1457. {
  1458.   BOOL done = FALSE;
  1459.   UWORD adr, end_adr, value;
  1460.  
  1461.   if (!expression(&adr))
  1462.     return;
  1463.   if (!expression(&end_adr))
  1464.     return;
  1465.   if (!expression(&value))
  1466.     return;
  1467.  
  1468.   do {
  1469.     if (adr == end_adr) done = TRUE;
  1470.  
  1471.     SAMWriteByte(adr++, value);
  1472.   } while (!done);
  1473. }
  1474.  
  1475.  
  1476. /*
  1477.  *  Vergleichen
  1478.  *  c start end dest
  1479.  */
  1480.  
  1481. void compare(void)
  1482. {
  1483.   BOOL done = FALSE;
  1484.   UWORD adr, end_adr, dest;
  1485.   int num = 0;
  1486.  
  1487.   if (!expression(&adr))
  1488.     return;
  1489.   if (!expression(&end_adr))
  1490.     return;
  1491.   if (!expression(&dest))
  1492.     return;
  1493.  
  1494.   do {
  1495.     if (adr == end_adr) done = TRUE;
  1496.  
  1497.     if (SAMReadByte(adr) != SAMReadByte(dest)) {
  1498.       FPrintf(fout, "%04lx ", adr);
  1499.       num++;
  1500.       if (!(num & 7))
  1501.         FPutC(fout, '\n');
  1502.     }
  1503.     adr++; dest++;
  1504.   } while (!done && !aborted());
  1505.  
  1506.   if (num & 7)
  1507.     FPutC(fout, '\n');
  1508.   FPrintf(fout, "%ld byte(s) different\n", num);
  1509. }
  1510.  
  1511.  
  1512. /*
  1513.  *  Kopieren
  1514.  *  t start end dest
  1515.  */
  1516.  
  1517. void transfer(void)
  1518. {
  1519.   BOOL done = FALSE;
  1520.   UWORD adr, end_adr, dest;
  1521.  
  1522.   if (!expression(&adr))
  1523.     return;
  1524.   if (!expression(&end_adr))
  1525.     return;
  1526.   if (!expression(&dest))
  1527.     return;
  1528.  
  1529.   if (dest < adr)
  1530.     do {
  1531.       if (adr == end_adr) done = TRUE;
  1532.       SAMWriteByte(dest++,SAMReadByte(adr++));
  1533.     } while (!done);
  1534.   else {
  1535.     dest += end_adr - adr;
  1536.     do {
  1537.       if (adr == end_adr) done = TRUE;
  1538.       SAMWriteByte(dest--,SAMReadByte(end_adr--));
  1539.     } while (!done);
  1540.   }
  1541. }
  1542.  
  1543.  
  1544. /*
  1545.  *  Speicher ändern
  1546.  *  : addr {byte}
  1547.  */
  1548.  
  1549. void modify(void)
  1550. {
  1551.   UWORD adr, val;
  1552.  
  1553.   if (!expression(&adr))
  1554.     return;
  1555.  
  1556.   while (the_token != T_END)
  1557.     if (expression(&val))
  1558.       SAMWriteByte(adr++, val);
  1559.     else
  1560.       return;
  1561. }
  1562.  
  1563.  
  1564. /*
  1565.  *  Ausdruck berechnen und anzeigen
  1566.  *  ? expression
  1567.  */
  1568.  
  1569. void print_expr(void)
  1570. {
  1571.   UWORD val;
  1572.  
  1573.   if (!expression(&val))
  1574.     return;
  1575.  
  1576.   FPrintf(fout, "Hex: %04lx\nDec: %lu\n", val, val);
  1577. }
  1578.  
  1579.  
  1580. /*
  1581.  *  Ausgabe umleiten
  1582.  *  o ["file"]
  1583.  */
  1584.  
  1585. void redir_output(void)
  1586. {
  1587.   // Alte Datei schließen
  1588.   if (fout != ferr) {
  1589.     Close(fout);
  1590.     fout = ferr;
  1591.     return;
  1592.   }
  1593.  
  1594.   // Kein Argument angegeben, dann weiter nichts tun
  1595.   if (the_token == T_END)
  1596.     return;
  1597.  
  1598.   // Sonst Datei öffnen
  1599.   if (the_token == T_STRING) {
  1600.     if (!(fout = Open(the_string, MODE_NEWFILE)))
  1601.       error("Unable to open file");
  1602.   } else
  1603.     error("'\"' around file name expected");
  1604. }
  1605.  
  1606.  
  1607. /*
  1608.  *  Interrupt-Vektoren anzeigen
  1609.  */
  1610.  
  1611. void int_vectors(void)
  1612. {
  1613.   FPuts(fout, "        IRQ  BRK  NMI\n");
  1614.   FPrintf(fout, "6510  : %04lx %04lx %04lx\n",
  1615.     SAMReadByte(0xffff) << 8 | SAMReadByte(0xfffe),
  1616.     SAMReadByte(0xffff) << 8 | SAMReadByte(0xfffe),
  1617.     SAMReadByte(0xfffb) << 8 | SAMReadByte(0xfffa));
  1618.  
  1619.   if (SAMMemConfig & 2)
  1620.     FPrintf(fout, "Kernal: %04lx %04lx %04lx\n",
  1621.       SAMReadByte(0x0315) << 8 | SAMReadByte(0x0314),
  1622.       SAMReadByte(0x0317) << 8 | SAMReadByte(0x0316),
  1623.       SAMReadByte(0x0319) << 8 | SAMReadByte(0x0318));
  1624. }
  1625.  
  1626.  
  1627. /*
  1628.  *  Zustand der Customchips anzeigen
  1629.  */
  1630.  
  1631. void view_state(void)
  1632. {
  1633.   switch (get_char()) {
  1634.     case 'c':        // CIA
  1635.       view_cia_state();
  1636.       break;
  1637.  
  1638.     case 's':        // SID
  1639.       view_sid_state();
  1640.       break;
  1641.  
  1642.     case 'v':        // VIC
  1643.       view_vic_state();
  1644.       break;
  1645.  
  1646.     default:
  1647.       error("Unknown command");
  1648.       break;
  1649.   }
  1650. }
  1651.  
  1652. void view_cia_state(void)
  1653. {
  1654.   CIADump cd;
  1655.  
  1656.   switch (get_char()) {
  1657.     case '1':
  1658.       GetCIA1Dump(&cd);
  1659.       break;
  1660.     case '2':
  1661.       GetCIA2Dump(&cd);
  1662.       break;
  1663.     default:
  1664.       error("Unknown command");
  1665.       return;
  1666.   }
  1667.  
  1668.   FPrintf(fout, "Timer A  : %s\n", cd.cra & 1 ? "On" : "Off");
  1669.   FPrintf(fout, " Counter : %04lx  Latch: %04lx\n", (cd.ta_hi << 8) | cd.ta_lo, (cd.ltcha_hi << 8) | cd.ltcha_lo);
  1670.   FPrintf(fout, " Run mode: %s\n", cd.cra & 8 ? "One-shot" : "Continuous");
  1671.   FPrintf(fout, " Input   : %s\n", cd.cra & 0x20 ? "CNT" : "ø2");
  1672.   FPuts(fout, " Output  : ");
  1673.   if (cd.cra & 2)
  1674.     if (cd.cra & 4)
  1675.       FPuts(fout, "PB6 Toggle\n\n");
  1676.     else
  1677.       FPuts(fout, "PB6 Pulse\n\n");
  1678.   else
  1679.     FPuts(fout, "None\n\n");
  1680.  
  1681.   FPrintf(fout, "Timer B  : %s\n", cd.crb & 1 ? "On" : "Off");
  1682.   FPrintf(fout, " Counter : %04lx  Latch: %04lx\n", (cd.tb_hi << 8) | cd.tb_lo, (cd.ltchb_hi << 8) | cd.ltchb_lo);
  1683.   FPrintf(fout, " Run mode: %s\n", cd.crb & 8 ? "One-shot" : "Continuous");
  1684.   FPuts(fout, " Input   : ");
  1685.   if (cd.crb & 0x40)
  1686.     if (cd.crb & 0x20)
  1687.       FPuts(fout, "Timer A underflow (CNT high)\n");
  1688.     else
  1689.       FPuts(fout, "Timer A underflow\n");
  1690.   else
  1691.     if (cd.crb & 0x20)
  1692.       FPuts(fout, "CNT\n");
  1693.     else
  1694.       FPuts(fout, "ø2\n");
  1695.   FPuts(fout, " Output  : ");
  1696.   if (cd.crb & 2)
  1697.     if (cd.crb & 4)
  1698.       FPuts(fout, "PB7 Toggle\n\n");
  1699.     else
  1700.       FPuts(fout, "PB7 Pulse\n\n");
  1701.   else
  1702.     FPuts(fout, "None\n\n");
  1703.  
  1704.   FPrintf(fout, "TOD         : %lx%lx:%lx%lx:%lx%lx.%lx %s\n",
  1705.     (cd.tod_hr >> 4) & 1, cd.tod_hr & 0x0f,
  1706.     (cd.tod_min >> 4) & 7, cd.tod_min & 0x0f,
  1707.     (cd.tod_sec >> 4) & 7, cd.tod_sec & 0x0f,
  1708.     cd.tod_10ths & 0x0f, cd.tod_hr & 0x80 ? "PM" : "AM");
  1709.   FPrintf(fout, "Alarm       : %lx%lx:%lx%lx:%lx%lx.%lx %s\n",
  1710.     (cd.alm_hr >> 4) & 1, cd.alm_hr & 0x0f,
  1711.     (cd.alm_min >> 4) & 7, cd.alm_min & 0x0f,
  1712.     (cd.alm_sec >> 4) & 7, cd.alm_sec & 0x0f,
  1713.     cd.alm_10ths & 0x0f, cd.alm_hr & 0x80 ? "PM" : "AM");
  1714.   FPrintf(fout, "TOD input   : %s\n", cd.cra & 0x80 ? "50Hz" : "60Hz");
  1715.   FPrintf(fout, "Write to    : %s registers\n\n", cd.crb & 0x80 ? "Alarm" : "TOD");
  1716.  
  1717.   FPrintf(fout, "Serial data : %02lx\n", cd.sdr);
  1718.   FPrintf(fout, "Serial mode : %s\n\n", cd.cra & 0x40 ? "Output" : "Input");
  1719.  
  1720.   FPuts(fout, "Pending int.: ");
  1721.   dump_cia_ints(cd.int_data);
  1722.   FPuts(fout, "Enabled int.: ");
  1723.   dump_cia_ints(cd.int_mask);
  1724. }
  1725.  
  1726. void dump_cia_ints(UBYTE int)
  1727. {
  1728.   if (int & 0x1f) {
  1729.     if (int & 1) FPuts(fout, "TA ");
  1730.     if (int & 2) FPuts(fout, "TB ");
  1731.     if (int & 4) FPuts(fout, "Alarm ");
  1732.     if (int & 8) FPuts(fout, "Serial ");
  1733.     if (int & 0x10) FPuts(fout, "Flag");
  1734.   } else
  1735.     FPuts(fout, "None");
  1736.   FPutC(fout, '\n');
  1737. }
  1738.  
  1739. void view_sid_state(void)
  1740. {
  1741.   SIDDump sd;
  1742.  
  1743.   GetSIDDump(&sd);
  1744.  
  1745.   FPuts(fout, "Voice 1\n");
  1746.   FPrintf(fout, " Frequency  : %04lx\n", (sd.freq_hi_1 << 8) | sd.freq_lo_1);
  1747.   FPrintf(fout, " Pulse Width: %04lx\n", ((sd.pw_hi_1 & 0x0f) << 8) | sd.pw_lo_1);
  1748.   FPrintf(fout, " Env. (ADSR): %lx %lx %lx %lx\n", sd.AD_1 >> 4, sd.AD_1 & 0x0f, sd.SR_1 >> 4, sd.SR_1 & 0x0f);
  1749.   FPuts(fout, " Waveform   : ");
  1750.   dump_sid_waveform(sd.ctrl_1);
  1751.   FPrintf(fout, " Gate       : %s  Ring mod.: %s\n", sd.ctrl_1 & 0x01 ? "On " : "Off", sd.ctrl_1 & 0x04 ? "On" : "Off");
  1752.   FPrintf(fout, " Test bit   : %s  Synchron.: %s\n", sd.ctrl_1 & 0x08 ? "On " : "Off", sd.ctrl_1 & 0x02 ? "On" : "Off");
  1753.   FPrintf(fout, " Filter     : %s\n", sd.res_filt & 0x01 ? "On" : "Off");
  1754.  
  1755.   FPuts(fout, "\nVoice 2\n");
  1756.   FPrintf(fout, " Frequency  : %04lx\n", (sd.freq_hi_2 << 8) | sd.freq_lo_2);
  1757.   FPrintf(fout, " Pulse Width: %04lx\n", ((sd.pw_hi_2 & 0x0f) << 8) | sd.pw_lo_2);
  1758.   FPrintf(fout, " Env. (ADSR): %lx %lx %lx %lx\n", sd.AD_2 >> 4, sd.AD_2 & 0x0f, sd.SR_2 >> 4, sd.SR_2 & 0x0f);
  1759.   FPuts(fout, " Waveform   : ");
  1760.   dump_sid_waveform(sd.ctrl_2);
  1761.   FPrintf(fout, " Gate       : %s  Ring mod.: %s\n", sd.ctrl_2 & 0x01 ? "On " : "Off", sd.ctrl_2 & 0x04 ? "On" : "Off");
  1762.   FPrintf(fout, " Test bit   : %s  Synchron.: %s\n", sd.ctrl_2 & 0x08 ? "On " : "Off", sd.ctrl_2 & 0x02 ? "On" : "Off");
  1763.   FPrintf(fout, " Filter     : %s\n", sd.res_filt & 0x02 ? "On" : "Off");
  1764.  
  1765.   FPuts(fout, "\nVoice 3\n");
  1766.   FPrintf(fout, " Frequency  : %04lx\n", (sd.freq_hi_3 << 8) | sd.freq_lo_3);
  1767.   FPrintf(fout, " Pulse Width: %04lx\n", ((sd.pw_hi_3 & 0x0f) << 8) | sd.pw_lo_3);
  1768.   FPrintf(fout, " Env. (ADSR): %lx %lx %lx %lx\n", sd.AD_3 >> 4, sd.AD_3 & 0x0f, sd.SR_3 >> 4, sd.SR_3 & 0x0f);
  1769.   FPuts(fout, " Waveform   : ");
  1770.   dump_sid_waveform(sd.ctrl_3);
  1771.   FPrintf(fout, " Gate       : %s  Ring mod.: %s\n", sd.ctrl_3 & 0x01 ? "On " : "Off", sd.ctrl_3 & 0x04 ? "On" : "Off");
  1772.   FPrintf(fout, " Test bit   : %s  Synchron.: %s\n", sd.ctrl_3 & 0x08 ? "On " : "Off", sd.ctrl_3 & 0x02 ? "On" : "Off");
  1773.   FPrintf(fout, " Filter     : %s  Mute     : %s\n", sd.res_filt & 0x04 ? "On" : "Off", sd.mode_vol & 0x80 ? "Yes" : "No");
  1774.  
  1775.   FPuts(fout, "\nFilters/Volume\n");
  1776.   FPrintf(fout, " Frequency: %04lx\n", (sd.fc_hi << 3) | (sd.fc_lo & 0x07));
  1777.   FPrintf(fout, " Resonance: %lx\n", sd.res_filt >> 4);
  1778.   FPuts(fout, " Mode     : ");
  1779.   if (sd.mode_vol & 0x70) {
  1780.     if (sd.mode_vol & 0x10) FPuts(fout, "Low-pass ");
  1781.     if (sd.mode_vol & 0x20) FPuts(fout, "Band-pass ");
  1782.     if (sd.mode_vol & 0x40) FPuts(fout, "High-pass");
  1783.   } else
  1784.     FPuts(fout, "None");
  1785.   FPrintf(fout, "\n Volume   : %lx\n", sd.mode_vol & 0x0f);
  1786. }
  1787.  
  1788. void dump_sid_waveform(UBYTE wave)
  1789. {
  1790.   if (wave & 0xf0) {
  1791.     if (wave & 0x10) FPuts(fout, "Triangle ");
  1792.     if (wave & 0x20) FPuts(fout, "Sawtooth ");
  1793.     if (wave & 0x40) FPuts(fout, "Rectangle ");
  1794.     if (wave & 0x80) FPuts(fout, "Noise");
  1795.   } else
  1796.     FPuts(fout, "None");
  1797.   FPutC(fout, '\n');
  1798. }
  1799.  
  1800. void view_vic_state(void)
  1801. {
  1802.   VICDump vd;
  1803.   short i;
  1804.  
  1805.   GetVICDump(&vd);
  1806.  
  1807.   FPrintf(fout, "Raster line       : %04lx\n", vd.raster | ((vd.ctrl1 & 0x80) << 1));
  1808.   FPrintf(fout, "IRQ raster line   : %04lx\n\n", vd.irq_raster);
  1809.  
  1810.   FPrintf(fout, "X scroll          : %ld\n", vd.ctrl2 & 7);
  1811.   FPrintf(fout, "Y scroll          : %ld\n", vd.ctrl1 & 7);
  1812.   FPrintf(fout, "Horizontal border : %ld columns\n", vd.ctrl2 & 8 ? 40 : 38);
  1813.   FPrintf(fout, "Vertical border   : %ld rows\n\n", vd.ctrl1 & 8 ? 25 : 24);
  1814.  
  1815.   FPuts(fout, "Display mode      : ");
  1816.   switch (((vd.ctrl1 >> 5) & 3) | ((vd.ctrl2 >> 2) & 4)) {
  1817.     case 0:
  1818.       FPuts(fout, "Standard text\n");
  1819.       break;
  1820.     case 1:
  1821.       FPuts(fout, "Multicolor text\n");
  1822.       break;
  1823.     case 2:
  1824.       FPuts(fout, "Standard bitmap\n");
  1825.       break;
  1826.     case 3:
  1827.       FPuts(fout, "Multicolor bitmap\n");
  1828.       break;
  1829.     case 4:
  1830.       FPuts(fout, "ECM text\n");
  1831.       break;
  1832.     case 5:
  1833.       FPuts(fout, "Invalid text (ECM+MCM)\n");
  1834.       break;
  1835.     case 6:
  1836.       FPuts(fout, "Invalid bitmap (ECM+BMM)\n");
  1837.       break;
  1838.     case 7:
  1839.       FPuts(fout, "Invalid bitmap (ECM+BMM+ECM)\n");
  1840.       break;
  1841.   }
  1842.   FPrintf(fout, "Sequencer state   : %s\n", vd.idle_state ? "Idle" : "Display");
  1843.   FPrintf(fout, "Bad line state    : %s\n", vd.bad_line ? "Yes" : "No");
  1844.   FPrintf(fout, "Bad lines enabled : %s\n", vd.bad_line_enable ? "Yes" : "No");
  1845.   FPrintf(fout, "Video counter     : %04lx\n", vd.vc);
  1846.   FPrintf(fout, "Video counter base: %04lx\n", vd.vcbase);
  1847.   FPrintf(fout, "Row counter       : %ld\n\n", vd.rc);
  1848.  
  1849.   FPrintf(fout, "VIC bank          : %04lx-%04lx\n", vd.bank_base, vd.bank_base + 0x3fff);
  1850.   FPrintf(fout, "Video matrix base : %04lx\n", vd.matrix_base);
  1851.   FPrintf(fout, "Character base    : %04lx\n", vd.char_base);
  1852.   FPrintf(fout, "Bitmap base       : %04lx\n\n", vd.bitmap_base);
  1853.  
  1854.   FPrintf(fout, "         Spr.0  Spr.1  Spr.2  Spr.3  Spr.4  Spr.5  Spr.6  Spr.7\n");
  1855.   FPuts(fout, "Enabled: "); dump_spr_flags(vd.me);
  1856.   FPrintf(fout, "Data   : %04lx   %04lx   %04lx   %04lx   %04lx   %04lx   %04lx   %04lx\n",
  1857.     vd.sprite_base[0], vd.sprite_base[1], vd.sprite_base[2], vd.sprite_base[3],
  1858.     vd.sprite_base[4], vd.sprite_base[5], vd.sprite_base[6], vd.sprite_base[7]);
  1859.   FPrintf(fout, "MC     : %02lx     %02lx     %02lx     %02lx     %02lx     %02lx     %02lx     %02lx\n",
  1860.     vd.mc[0], vd.mc[1], vd.mc[2], vd.mc[3], vd.mc[4], vd.mc[5], vd.mc[6], vd.mc[7]);
  1861.  
  1862.   FPuts(fout, "Mode   : ");
  1863.   for (i=0; i<8; i++)
  1864.     if (vd.mmc & (1<<i))
  1865.       FPuts(fout, "Multi  ");
  1866.     else
  1867.       FPuts(fout, "Std.   ");
  1868.  
  1869.   FPuts(fout, "\nX-Exp. : "); dump_spr_flags(vd.mxe);
  1870.   FPuts(fout, "Y-Exp. : "); dump_spr_flags(vd.mye);
  1871.  
  1872.   FPuts(fout, "Prio.  : ");
  1873.   for (i=0; i<8; i++)
  1874.     if (vd.mdp & (1<<i))
  1875.       FPuts(fout, "Back   ");
  1876.     else
  1877.       FPuts(fout, "Fore   ");
  1878.  
  1879.   FPuts(fout, "\n\nPending interrupts: ");
  1880.   dump_vic_ints(vd.irq_flag);
  1881.   FPuts(fout, "Enabled interrupts: ");
  1882.   dump_vic_ints(vd.irq_mask);
  1883. }
  1884.  
  1885. void dump_spr_flags(UBYTE f)
  1886. {
  1887.   short i;
  1888.  
  1889.   for (i=0; i<8; i++)
  1890.     if (f & (1<<i))
  1891.       FPuts(fout, "Yes    ");
  1892.     else
  1893.       FPuts(fout, "No     ");
  1894.  
  1895.   FPutC(fout, '\n');
  1896. }
  1897.  
  1898. void dump_vic_ints(UBYTE int)
  1899. {
  1900.   if (int & 0x1f) {
  1901.     if (int & 1) FPuts(fout, "Raster ");
  1902.     if (int & 2) FPuts(fout, "Spr-Data ");
  1903.     if (int & 4) FPuts(fout, "Spr-Spr ");
  1904.     if (int & 8) FPuts(fout, "Lightpen");
  1905.   } else
  1906.     FPuts(fout, "None");
  1907.   FPutC(fout, '\n');
  1908. }
  1909.  
  1910.  
  1911. /*
  1912.  *  Daten laden
  1913.  *  l start "file"
  1914.  */
  1915.  
  1916. void load_data(void)
  1917. {
  1918.   UWORD adr;
  1919.   BPTR file;
  1920.   LONG fc;
  1921.  
  1922.   if (!expression(&adr))
  1923.     return;
  1924.   if (the_token == T_END) {
  1925.     error("Missing file name");
  1926.     return;
  1927.   }
  1928.   if (the_token != T_STRING) {
  1929.     error("'\"' around file name expected");
  1930.     return;
  1931.   }
  1932.  
  1933.   if (!(file = Open(the_string, MODE_OLDFILE)))
  1934.     error("Unable to open file");
  1935.   else {
  1936.     while ((fc = FGetC(file)) >= 0)
  1937.       SAMWriteByte(adr++, fc);
  1938.     Close(file);
  1939.   }
  1940. }
  1941.  
  1942.  
  1943. /*
  1944.  *  Daten speichern
  1945.  *  s start end "file"
  1946.  */
  1947.  
  1948. void save_data(void)
  1949. {
  1950.   BOOL done = FALSE;
  1951.   UWORD adr, end_adr;
  1952.   BPTR file;
  1953.  
  1954.   if (!expression(&adr))
  1955.     return;
  1956.   if (!expression(&end_adr))
  1957.     return;
  1958.   if (the_token == T_END) {
  1959.     error("Missing file name");
  1960.     return;
  1961.   }
  1962.   if (the_token != T_STRING) {
  1963.     error("'\"' around file name expected");
  1964.     return;
  1965.   }
  1966.  
  1967.   if (!(file = Open(the_string, MODE_NEWFILE)))
  1968.     error("Unable to create file");
  1969.   else {
  1970.     do {
  1971.       if (adr == end_adr) done = TRUE;
  1972.  
  1973.       FPutC(file, SAMReadByte(adr++));
  1974.     } while (!done);
  1975.     Close(file);
  1976.   }
  1977. }
  1978.